﻿using System;
using System.Collections.Generic;
using System.Linq;

#region Personnal using
using Microsoft.Xna.Framework.Input;
using FlanProjectData.Helpers;
#endregion

namespace FlanProjectData.Managers
{
    public class InputManager
    {
        private static Logger logger = new Logger("InputManager");
        private static Keys[] prevPressedKeys;

        #region Action Enum

        /// <summary>
        /// Contains actions possible in the game
        /// </summary>
        public enum Action
        {
            None,
            Ok,
            Return,
            Exit,
            MoveUp,
            MoveDown,
            MoveLeft,
            MoveRight,
            Attack,
            Defend,
            Skill,
            Up,
            Down,
            Right,
            Left,
            Save,
            TotalActionCount
        }

        /// <summary>
        /// Associate enum action to a string name
        /// </summary>
        private static readonly string[] actionNames =
		{
			"Ok",
			"Exit",
            "MoveLeft",
            "MoveRight",
            "Attack"
		};

        /// <summary>
        /// Return the string name of the corresponding action
        /// </summary>
        public static string GetActionName(Action a)
        {
            int index = (int)a;

            if ((index < 0) || (index > actionNames.Length))
            {
                throw new ArgumentException("Invalid action");
            }

            return actionNames[index];
        }

        #endregion

        #region Action Map


        /// <summary>
        /// Contains all listed key
        /// </summary>
        public class ActionMap
        {
            public List<Keys> keyboardKeys = new List<Keys>();
        }

        #endregion

        #region Action Mapping

        public static ActionMap[] ActionMaps { get; set; }

        public static void ResetActionMaps()
        {
            ActionMaps = new ActionMap[(int)Action.TotalActionCount];

            ActionMaps[(int)Action.None] = new ActionMap();

            ActionMaps[(int)Action.Ok] = new ActionMap();
            ActionMaps[(int)Action.Ok].keyboardKeys.Add(Keys.Enter);

            ActionMaps[(int)Action.Exit] = new ActionMap();
            ActionMaps[(int)Action.Exit].keyboardKeys.Add(Keys.Escape);

            ActionMaps[(int)Action.MoveUp] = new ActionMap();
            ActionMaps[(int)Action.MoveUp].keyboardKeys.Add(Keys.Up);

            ActionMaps[(int)Action.MoveDown] = new ActionMap();
            ActionMaps[(int)Action.MoveDown].keyboardKeys.Add(Keys.Down);

            ActionMaps[(int)Action.MoveLeft] = new ActionMap();
            ActionMaps[(int)Action.MoveLeft].keyboardKeys.Add(Keys.Left);

            ActionMaps[(int)Action.MoveRight] = new ActionMap();
            ActionMaps[(int)Action.MoveRight].keyboardKeys.Add(Keys.Right);

            ActionMaps[(int)Action.Attack] = new ActionMap();
            ActionMaps[(int)Action.Attack].keyboardKeys.Add(Keys.A);

            ActionMaps[(int)Action.Defend] = new ActionMap();
            ActionMaps[(int)Action.Defend].keyboardKeys.Add(Keys.LeftShift);

            ActionMaps[(int)Action.Skill] = new ActionMap();
            ActionMaps[(int)Action.Skill].keyboardKeys.Add(Keys.Z);

            ActionMaps[(int)Action.Up] = new ActionMap();
            ActionMaps[(int)Action.Up].keyboardKeys.Add(Keys.Up);

            ActionMaps[(int)Action.Down] = new ActionMap();
            ActionMaps[(int)Action.Down].keyboardKeys.Add(Keys.Down);

            ActionMaps[(int)Action.Left] = new ActionMap();
            ActionMaps[(int)Action.Left].keyboardKeys.Add(Keys.Left);

            ActionMaps[(int)Action.Right] = new ActionMap();
            ActionMaps[(int)Action.Right].keyboardKeys.Add(Keys.Right);

            ActionMaps[(int)Action.Return] = new ActionMap();
            ActionMaps[(int)Action.Return].keyboardKeys.Add(Keys.Back);

            ActionMaps[(int)Action.Save] = new ActionMap();
            ActionMaps[(int)Action.Save].keyboardKeys.Add(Keys.S);
        }


        #endregion

        #region Keyboard Data

        /// <summary>
        /// Define the current state of the keyboard
        /// </summary>
        public static KeyboardState CurrentKeyboardState { get; set; }

        /// <summary>
        /// Define the previous state of the keyboard
        /// </summary>
        public static KeyboardState PreviousKeyboardState { get; set; }

        /// <summary>
        /// Define if the keys is pressed
        /// </summary>
        public static bool IsKeyPressed(Keys k)
        {
            return CurrentKeyboardState.IsKeyDown(k);
        }

        public static bool IsPreviousKeyPressed(Keys k)
        {
            return PreviousKeyboardState.IsKeyDown(k);
        }

        /// <summary>
        /// Define if the key is triggered
        /// </summary>
        public static bool IsKeyTriggered(Keys k)
        {
            return (CurrentKeyboardState.IsKeyDown(k) &&
                (!PreviousKeyboardState.IsKeyDown(k)));
        }

        /// <summary>
        /// get the key's name which is pressed
        /// </summary>
        public static String getKeyPressed()
        {
            String text = "";
            KeyboardState keyboardState = Keyboard.GetState();
            Keys[] pressedKeys = keyboardState.GetPressedKeys();

            bool shiftPressed;

            shiftPressed = keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift);


            foreach (Keys key in pressedKeys)
            {
                if (InputManager.prevPressedKeys != null)
                {
                    if (!prevPressedKeys.Contains(key))
                    {
                        string keyString = key.ToString();

                        if (keyString.Length == 1)
                        {
                            char c = keyString[0];

                            if (!shiftPressed)
                                c += (char)('a' - 'A');

                            text += "" + c;
                        }
                    }
                }
            }

            prevPressedKeys = pressedKeys;
            return text;
        }

        #endregion

        #region Action Test

        public static bool IsActionPressed(Action a)
        {
            return IsActionMapPressed(ActionMaps[(int)a]);
        }

        public static bool IsPreviousActionPressed(Action a)
        {
            return IsPreviousActionMapPressed(ActionMaps[(int)a]);
        }

        public static bool IsActionTriggered(Action a)
        {
            return IsActionMapTriggered(ActionMaps[(int)a]);
        }

        private static bool IsActionMapPressed(ActionMap a)
        {
            for (int i = 0; i < a.keyboardKeys.Count; i++)
            {
                if (IsKeyPressed(a.keyboardKeys[i]))
                {
                    return true;
                }
            }
            return false;
        }

        private static bool IsPreviousActionMapPressed(ActionMap a)
        {
            for (int i = 0; i < a.keyboardKeys.Count; i++)
            {
                if (IsPreviousKeyPressed(a.keyboardKeys[i]))
                {
                    return true;
                }
            }
            return false;
        }

        private static bool IsActionMapTriggered(ActionMap a)
        {
            for (int i = 0; i < a.keyboardKeys.Count; i++)
            {
                if (IsKeyTriggered(a.keyboardKeys[i]))
                {
                    return true;
                }
            }
            return false;
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Initialize the input manager with default keys
        /// </summary>
        public static void Initialize()
        {
            ResetActionMaps();
        }

        #endregion

        #region Updating

        /// <summary>
        /// Update with the last keyboard event
        /// </summary>
        public static void Update()
        {
            PreviousKeyboardState = CurrentKeyboardState;
            CurrentKeyboardState = Keyboard.GetState();
        }

        #endregion
    }
}
